package com.puzzle;

import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ContentUris;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler.Callback;
import android.os.Message;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AbsoluteLayout;
import android.widget.PopupMenu;
import android.widget.PopupMenu.OnMenuItemClickListener;
import android.widget.Toast;

import androidx.core.app.ActivityCompat;

import java.io.File;
import java.io.FileInputStream;
import java.util.Objects;

// 主活动
public class MainActivity extends Activity implements Callback, OnMenuItemClickListener {
    /**
     * 难度选择类。
     */
    private class DifficultyChooser implements DialogInterface.OnClickListener {
        private final int mMenuItemId;  // 用户单击的菜单项的 id

        /**
         * 构造方法。
         * @param id    用户单击的菜单项的 id
         */
        public DifficultyChooser(int id) {
            mMenuItemId = id;
        }

        /**
         * 用户单击对话框上的按钮的响应方法。
         * @param dialog        对话框
         * @param clickedButton 为 DialogInterface.BUTTON_POSITIVE 表示用户单击的是"确定"按钮
         *                      为 DialogInterface.BUTTON_NEGATIVE 表示用户单击的是"取消"按钮
         */
        @Override
        public void onClick(DialogInterface dialog, int clickedButton) {
            if (clickedButton == DialogInterface.BUTTON_POSITIVE) {
                MainActivity.this.setDifficulty(mMenuItemId);
            } else if (clickedButton == DialogInterface.BUTTON_NEGATIVE) {
                dialog.cancel();
            }
        }
    }

    /**
     * 图片选择类。
     */
    private class PictureChooser implements DialogInterface.OnClickListener {
        /**
         * 用户单击对话框上的按钮的响应方法。
         * @param dialog        对话框
         * @param clickedButton 为 DialogInterface.BUTTON_POSITIVE 表示用户单击的是"确定"按钮
         *                      为 DialogInterface.BUTTON_NEGATIVE 表示用户单击的是"取消"按钮
         */
        @Override
        public void onClick(DialogInterface dialog, int clickedButton) {
            if (clickedButton == DialogInterface.BUTTON_POSITIVE) {
                MainActivity.this.setPicture();
            } else if (clickedButton == DialogInterface.BUTTON_NEGATIVE) {
                dialog.cancel();
            }
        }
    }

    private Game mGame;         // 游戏
    private PopupMenu mMenu;    // 菜单

    /**
     * 获取 URI 对应的文件路径(数据库表中的 _data 列)
     * @param uri           uri
     * @param selection     列
     * @param selectionArgs 列参数
     * @return 路径
     */
    private String getDataColumn(Uri uri, String selection, String[] selectionArgs) {
        String path = "";
        final String[] projection = new String[]{MediaStore.Images.Media.DATA};
        Cursor cursor = null;
        try {
            cursor = super.getContentResolver().query(uri, projection, selection, selectionArgs, null);
            if (cursor != null && cursor.moveToFirst()) {
                final int columnIndex = cursor.getColumnIndexOrThrow(projection[0]);
                path = cursor.getString(columnIndex);
            }
        } catch (Exception e) {
            if (cursor != null) {
                cursor.close();
            }
        }
        return path;
    }

    /**
     * 从系统文件选择器返回的 uri 中获取文件路径。
     * @param context   设备环境
     * @param uri       系统文件选择器返回的 uri
     * @return uri 对应的文件路径
     */
    private String getPathFromURI(Context context, Uri uri) {
        String filePath = "";

        // 如果是文档类型的 URI
        if (DocumentsContract.isDocumentUri(context, uri)) {
            // 通过 Document id 来进行处理
            final String documentId = DocumentsContract.getDocumentId(uri);
            final String authority = uri.getAuthority();

            assert authority != null;
            if (authority.equals("com.android.providers.media.documents")) {
                // 如果是本地图片
                // 使用':'分割
                final String id = documentId.split(":")[1];
                final String selection = MediaStore.Images.Media._ID + "=?";
                final String[] selectionArgs = {id};
                filePath = this.getDataColumn(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection, selectionArgs);
            } else if (authority.equals("com.android.providers.downloads.documents")) {
                // 如果是网络图片
                final Uri tempUri = Uri.parse("content://downloads/public_downloads");
                final Uri contentUri = ContentUris.withAppendedId(tempUri, Long.parseLong(documentId));
                filePath = this.getDataColumn(contentUri, null, null);
            }
        } else if (Objects.requireNonNull(uri.getScheme()).equalsIgnoreCase("content")) {
            // 如果是内容类型的 URI
            filePath = this.getDataColumn(uri, null, null);
        } else if (uri.getScheme().equalsIgnoreCase("file")) {
            // 如果是文件类型的 URI
            filePath = uri.getPath();
        }
        return filePath;
    }

    /**
     * 自定义事件的响应方法。
     * @param message   事件
     * @return 事件在此被处理则返回 true，否则返回 false
     */
    @Override
    public boolean handleMessage(Message message) {
        if (message.what == Const.UM_GAME_OVER) {
            this.onGameOver();
            return true;
        }
        return false;
    }

    /**
     * Activity 返回结果事件的响应方法。
     * @param requestCode   请求码
     * @param resultCode    结果码
     * @param data          数据
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode != Activity.RESULT_OK || data == null) {
            return;
        }

        // 加载图片
        final String filePath = this.getPathFromURI(this, data.getData());
        if (TextUtils.isEmpty(filePath)) {
            Toast.makeText(this, R.string.IDS_NOT_SUPPORT_IMAGE, Toast.LENGTH_LONG).show();
            return;
        }

        final File file = new File(filePath);
        Bitmap image = null;
        try {
            final FileInputStream fileInputStream = new FileInputStream(file);
            image = BitmapFactory.decodeStream(fileInputStream);
            fileInputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (image == null) {
            Toast.makeText(this, R.string.IDS_NOT_SUPPORT_IMAGE, Toast.LENGTH_LONG).show();
            return;
        }

        // 设置图片
        mGame.setPicture(image);

        super.onActivityResult(requestCode, resultCode, data);
    }

    /**
     * 菜单按钮的单击响应方法。
     * @param view  按钮
     */
    public void onButtonShowMenuClicked(View view) {
        // 弹出菜单
        mMenu.show();
    }

    /**
     * 创建事件的响应方法。
     * @param savedInstanceState    保存的实例状态
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        super.setContentView(R.layout.activity_main);
    }

    /**
     * 游戏结束事件的响应方法。
     */
    private void onGameOver() {
        // 显示胜利提示信息
        Toast.makeText(this, R.string.IDS_WON, Toast.LENGTH_LONG).show();
    }

    /**
     * 所有菜单项的单击响应方法。
     * @param menuItem  用户单击的菜单项
     * @return 事件在此被处理则返回 true，否则返回 false
     */
    @Override
    public boolean onMenuItemClick(MenuItem menuItem) {
        final int menuId = menuItem.getItemId();
        if (menuId == R.id.IDC_MENU_ITEM_START) {
            this.onMenuItemStartClicked();
            return true;
        }
        if (menuId == R.id.IDC_MENU_ITEM_EASY || menuId == R.id.IDC_MENU_ITEM_MEDIUM || menuId == R.id.IDC_MENU_ITEM_HARD) {
            this.onMenuItemSetDifficultyClicked(menuId);
            menuItem.setChecked(true);
            return true;
        }
        if (menuId == R.id.IDC_MENU_ITEM_HAS_BORDER || menuId == R.id.IDC_MENU_ITEM_NO_BORDER) {
            this.onMenuItemSetBorderClicked(menuId);
            menuItem.setChecked(true);
            return true;
        }
        if (menuId == R.id.IDC_MENU_ITEM_SET_PICTURE) {
            this.onMenuItemSetPictureClicked();
            return true;
        }
        return false;
    }

    /**
     * "图片边框"菜单项的单击响应方法。
     * @param id   用户单击的菜单项的 id
     */
    private void onMenuItemSetBorderClicked(int id) {
        // 如果要设置的参数与当前游戏参数相同，则直接返回
        final boolean hasBorder = id == R.id.IDC_MENU_ITEM_HAS_BORDER;
        if (hasBorder == mGame.pictureHasBorder()) {
            return;
        }

        // 设置边框
        mGame.setPictureBorder(hasBorder);
    }

    /**
     * "难度"菜单项的单击响应方法。
     * @param id    用户单击的菜单项的 id
     */
    private void onMenuItemSetDifficultyClicked(int id) {
        if (mGame.getStatus() != Game.Status.END) {
            new AlertDialog.Builder(this)
                .setMessage(R.string.IDS_RESET)
                .setPositiveButton(android.R.string.yes, new DifficultyChooser(id))
                .setNegativeButton(android.R.string.no, null)
                .show();
        } else {
            this.setDifficulty(id);
        }
    }

    /**
     * "换图片"菜单项的单击响应方法。
     */
    private void onMenuItemSetPictureClicked() {
        // 弹出询问对话框
        if (mGame.getStatus() != Game.Status.END) {
            new AlertDialog.Builder(this)
                .setMessage(R.string.IDS_RESET)
                .setPositiveButton(android.R.string.yes, new PictureChooser())
                .setNegativeButton(android.R.string.no, null)
                .show();
        } else {
            this.setPicture();
        }
    }

    /**
     * "开始"菜单项的单击响应方法。
     */
    private void onMenuItemStartClicked() {
        mGame.start();
    }

    /**
     * 焦点变化事件的响应方法。
     * @param hasFocus  获得焦点则返回 true，否则返回 false
     */
    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if (mGame == null) {
            // 请求读 SD 卡的权限
            final String[] permissionStorage = {Manifest.permission.READ_EXTERNAL_STORAGE};
            ActivityCompat.requestPermissions(this, permissionStorage, 1);

            // 创建主菜单
            mMenu = new PopupMenu(this, super.findViewById(R.id.IDC_BUTTON_SHOW_MENU));
            mMenu.setOnMenuItemClickListener(this);
            final Menu menu = mMenu.getMenu();
            super.getMenuInflater().inflate(R.menu.main, menu);

            // 创建游戏区域
            final AbsoluteLayout gameBoard = super.findViewById(R.id.IDC_GAME_BOARD);

            // 创建游戏
            mGame = new Game(this, gameBoard);

            // 弹出提示
            Toast.makeText(this, R.string.IDS_TIP_TEXT, Toast.LENGTH_LONG).show();
        }
    }

    /**
     * 设置难度。
     * @param id    用户单击的菜单项的 id
     */
    private void setDifficulty(int id) {
        // 如果要设置的参数与当前游戏参数相同，则直接返回
        Game.Difficulty newDiff = Game.Difficulty.EASY;
        if (id == R.id.IDC_MENU_ITEM_MEDIUM) {
            newDiff = Game.Difficulty.MEDIUM;
        } else if (id == R.id.IDC_MENU_ITEM_HARD) {
            newDiff = Game.Difficulty.HARD;
        }
        if (newDiff == mGame.getDifficulty()) {
            return;
        }

        // 设置难度
        mGame.setDifficulty(newDiff);
    }

    /**
     * 设置图片。
     */
    private void setPicture() {
        // 调用系统自带的文件管理器
        final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.setType("image/*");
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        super.startActivityForResult(intent, 1);
    }
}
